home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2007 January, February, March & April
/
Chip-Cover-CD-2007-02.iso
/
Pakiet multimedia
/
Muzyka
/
Edytory sampli (probek dzwieku)
/
ZynAddSubFX_2.2.0
/
Setup_ZynAddSubFX-2.2.0.exe
/
source code
/
Effects
/
Reverb.C
< prev
next >
Wrap
C/C++ Source or Header
|
2005-03-14
|
10KB
|
439 lines
/*
ZynAddSubFX - a software synthesizer
Reverb.C - Reverberation effect
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "Reverb.h"
/*TODO: EarlyReflections,Prdelay,Perbalance */
Reverb::Reverb(int insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_){
efxoutl=efxoutl_;
efxoutr=efxoutr_;
inputbuf=new REALTYPE[SOUND_BUFFER_SIZE];
filterpars=NULL;
insertion=insertion_;
//defaults
Ppreset=0;
Pvolume=48;
Ppan=64;
Ptime=64;
Pidelay=40;
Pidelayfb=0;
Prdelay=0;
Plpf=127;
Phpf=0;
Perbalance=64;
Plohidamp=80;
Ptype=1;
Proomsize=64;roomsize=1.0;rs=1.0;
for (int i=0;i<REV_COMBS*2;i++) {
comblen[i]=800+(int)(RND*1400);
combk[i]=0;
lpcomb[i]=0;
combfb[i]=-0.97;
comb[i]=NULL;
};
for (int i=0;i<REV_APS*2;i++) {
aplen[i]=500+(int)(RND*500);
apk[i]=0;
ap[i]=NULL;
};
lpf=NULL;hpf=NULL;//no filter
idelay=NULL;
setpreset(Ppreset);
cleanup();//do not call this before the comb initialisation
};
Reverb::~Reverb(){
int i;
if (idelay!=NULL) delete idelay;
if (hpf!=NULL) delete hpf;
if (lpf!=NULL) delete lpf;
for (i=0;i<REV_APS*2;i++) delete ap[i];
for (i=0;i<REV_COMBS*2;i++) delete comb[i];
delete [] inputbuf;
};
/*
* Cleanup the effect
*/
void Reverb::cleanup(){
int i,j;
for (i=0;i<REV_COMBS*2;i++){
lpcomb[i]=0.0;
for (j=0;j<comblen[i];j++) comb[i][j]=0.0;
};
for (i=0;i<REV_APS*2;i++)
for (j=0;j<aplen[i];j++) ap[i][j]=0.0;
if (idelay!=NULL) for (i=0;i<idelaylen;i++) idelay[i]=0.0;
if (hpf!=NULL) hpf->cleanup();
if (lpf!=NULL) lpf->cleanup();
};
/*
* Process one channel; 0=left,1=right
*/
void Reverb::processmono(int ch,REALTYPE *output){
int i,j;
REALTYPE fbout,tmp;
//TODO: implement the high part from lohidamp
for (j=REV_COMBS*ch;j<REV_COMBS*(ch+1);j++){
int ck=combk[j];
int comblength=comblen[j];
REALTYPE lpcombj=lpcomb[j];
for (i=0;i<SOUND_BUFFER_SIZE;i++){
fbout=comb[j][ck]*combfb[j];
fbout=fbout*(1.0-lohifb)+lpcombj*lohifb;
lpcombj=fbout;
comb[j][ck]=inputbuf[i]+fbout;
output[i]+=fbout;
if ((++ck)>=comblength) ck=0;
};
combk[j]=ck;
lpcomb[j]=lpcombj;
};
for (j=REV_APS*ch;j<REV_APS*(1+ch);j++){
int ak=apk[j];
int aplength=aplen[j];
for (i=0;i<SOUND_BUFFER_SIZE;i++){
tmp=ap[j][ak];
ap[j][ak]=0.7*tmp+output[i];
output[i]=tmp-0.7*ap[j][ak];
if ((++ak)>=aplength) ak=0;
};
apk[j]=ak;
};
};
/*
* Effect output
*/
void Reverb::out(REALTYPE *smps_l, REALTYPE *smps_r){
int i;
if ((Pvolume==0)&&(insertion!=0)) return;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
inputbuf[i]=(smps_l[i]+smps_r[i])/2.0;
//Initial delay r
if (idelay!=NULL){
REALTYPE tmp=inputbuf[i]+idelay[idelayk]*idelayfb;
inputbuf[i]=idelay[idelayk];
idelay[idelayk]=tmp;
idelayk++;if (idelayk>=idelaylen) idelayk=0;
};
};
if (lpf!=NULL) lpf->filterout(inputbuf);
if (hpf!=NULL) hpf->filterout(inputbuf);
processmono(0,efxoutl);//left
processmono(1,efxoutr);//right
REALTYPE lvol=rs/REV_COMBS*pan;
REALTYPE rvol=rs/REV_COMBS*(1.0-pan);
if (insertion!=0){
lvol*=2;rvol*=2;
};
for (int i=0;i<SOUND_BUFFER_SIZE;i++){
efxoutl[i]*=lvol;
efxoutr[i]*=rvol;
};
};
/*
* Parameter control
*/
void Reverb::setvolume(unsigned char Pvolume){
this->Pvolume=Pvolume;
if (insertion==0) {
outvolume=pow(0.01,(1.0-Pvolume/127.0))*4.0;
volume=1.0;
} else {
volume=outvolume=Pvolume/127.0;
if (Pvolume==0) cleanup();
};
};
void Reverb::setpan(unsigned char Ppan){
this->Ppan=Ppan;
pan=(REALTYPE)Ppan/127.0;
};
void Reverb::settime(unsigned char Ptime){
int i;
REALTYPE t;
this->Ptime=Ptime;
t=pow(60.0,(REALTYPE)Ptime/127.0)-0.97;
for (i=0;i<REV_COMBS*2;i++){
combfb[i]=-exp((REALTYPE)comblen[i]/(REALTYPE)SAMPLE_RATE*log(0.001)/t);
//the feedback is negative because it removes the DC
};
};
void Reverb::setlohidamp(unsigned char Plohidamp){
REALTYPE x;
if (Plohidamp<64) Plohidamp=64;//remove this when the high part from lohidamp will be added
this->Plohidamp=Plohidamp;
if (Plohidamp==64) {
lohidamptype=0;
lohifb=0.0;
} else {
if (Plohidamp<64) lohidamptype=1;
if (Plohidamp>64) lohidamptype=2;
x=fabs((REALTYPE)(Plohidamp-64)/64.1);
lohifb=x*x;
};
};
void Reverb::setidelay(unsigned char Pidelay){
REALTYPE delay;
this->Pidelay=Pidelay;
delay=pow(50*Pidelay/127.0,2)-1.0;
if (idelay!=NULL) delete (idelay);
idelay=NULL;
idelaylen=(int) (SAMPLE_RATE*delay/1000);
if (idelaylen>1) {
idelayk=0;
idelay=new REALTYPE[idelaylen];
for (int i=0;i<idelaylen;i++) idelay[i]=0.0;
};
};
void Reverb::setidelayfb(unsigned char Pidelayfb){
this->Pidelayfb=Pidelayfb;
idelayfb=Pidelayfb/128.0;
};
void Reverb::sethpf(unsigned char Phpf){
this->Phpf=Phpf;
if (Phpf==0) {//No HighPass
if (hpf!=NULL) delete(hpf);
hpf=NULL;
}
else{
REALTYPE fr=exp(pow(Phpf/127.0,0.5)*log(10000.0))+20.0;
if (hpf==NULL) hpf=new AnalogFilter(3,fr,1,0);
else hpf->setfreq(fr);
};
};
void Reverb::setlpf(unsigned char Plpf){
this->Plpf=Plpf;
if (Plpf==127) {//No LowPass
if (lpf!=NULL) delete(lpf);
lpf=NULL;
}
else{
REALTYPE fr=exp(pow(Plpf/127.0,0.5)*log(25000.0))+40;
if (lpf==NULL) lpf=new AnalogFilter(2,fr,1,0);
else lpf->setfreq(fr);
};
};
void Reverb::settype(unsigned char Ptype){
const int NUM_TYPES=2;
int combtunings[NUM_TYPES][REV_COMBS]={
//this is unused (for random)
{0,0,0,0,0,0,0,0},
//Freeverb by Jezar at Dreampoint
{1116,1188,1277,1356,1422,1491,1557,1617}
};
int aptunings[NUM_TYPES][REV_APS]={
//this is unused (for random)
{0,0,0,0},
//Freeverb by Jezar at Dreampoint
{225,341,441,556}
};
if (Ptype>=NUM_TYPES) Ptype=NUM_TYPES-1;
this->Ptype=Ptype;
REALTYPE tmp;
for (int i=0;i<REV_COMBS*2;i++) {
if (Ptype==0) tmp=800.0+(int)(RND*1400.0);
else tmp=combtunings[Ptype][i%REV_COMBS];
tmp*=roomsize;
if (i>REV_COMBS) tmp+=23.0;
tmp*=SAMPLE_RATE/44100.0;//adjust the combs according to the samplerate
if (tmp<10) tmp=10;
comblen[i]=(int) tmp;
combk[i]=0;
lpcomb[i]=0;
if (comb[i]!=NULL) delete comb[i];
comb[i]=new REALTYPE[comblen[i]];
};
for (int i=0;i<REV_APS*2;i++) {
if (Ptype==0) tmp=500+(int)(RND*500);
else tmp=aptunings[Ptype][i%REV_APS];
tmp*=roomsize;
if (i>REV_APS) tmp+=23.0;
tmp*=SAMPLE_RATE/44100.0;//adjust the combs according to the samplerate
if (tmp<10) tmp=10;
aplen[i]=(int) tmp;
apk[i]=0;
if (ap[i]!=NULL) delete ap[i];
ap[i]=new REALTYPE[aplen[i]];
};
settime(Ptime);
cleanup();
};
void Reverb::setroomsize(unsigned char Proomsize){
if (Proomsize==0) Proomsize=64;//this is because the older versions consider roomsize=0
this->Proomsize=Proomsize;
roomsize=(Proomsize-64.0)/64.0;
if (roomsize>0.0) roomsize*=2.0;
roomsize=pow(10.0,roomsize);
rs=sqrt(roomsize);
settype(Ptype);
};
void Reverb::setpreset(unsigned char npreset){
const int PRESET_SIZE=12;
const int NUM_PRESETS=13;
unsigned char presets[NUM_PRESETS][PRESET_SIZE]={
//Cathedral1
{80,64,63,24,0,0,0,85,5,83,1,64},
//Cathedral2
{80,64,69,35,0,0,0,127,0,71,0,64},
//Cathedral3
{80,64,69,24,0,0,0,127,75,78,1,85},
//Hall1
{90,64,51,10,0,0,0,127,21,78,1,64},
//Hall2
{90,64,53,20,0,0,0,127,75,71,1,64},
//Room1
{100,64,33,0,0,0,0,127,0,106,0,30},
//Room2
{100,64,21,26,0,0,0,62,0,77,1,45},
//Basement
{110,64,14,0,0,0,0,127,5,71,0,25},
//Tunnel
{85,80,84,20,42,0,0,51,0,78,1,105},
//Echoed1
{95,64,26,60,71,0,0,114,0,64,1,64},
//Echoed2
{90,64,40,88,71,0,0,114,0,88,1,64},
//VeryLong1
{90,64,93,15,0,0,0,114,0,77,0,95},
//VeryLong2
{90,64,111,30,0,0,0,114,90,74,1,80}};
if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1;
for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]);
if (insertion!=0) changepar(0,presets[npreset][0]/2);//lower the volume if reverb is insertion effect
Ppreset=npreset;
};
void Reverb::changepar(int npar,unsigned char value){
switch (npar){
case 0: setvolume(value);
break;
case 1: setpan(value);
break;
case 2: settime(value);
break;
case 3: setidelay(value);
break;
case 4: setidelayfb(value);
break;
// case 5: setrdelay(value);
// break;
// case 6: seterbalance(value);
// break;
case 7: setlpf(value);
break;
case 8: sethpf(value);
break;
case 9: setlohidamp(value);
break;
case 10:settype(value);
break;
case 11:setroomsize(value);
break;
};
};
unsigned char Reverb::getpar(int npar){
switch (npar){
case 0: return(Pvolume);
break;
case 1: return(Ppan);
break;
case 2: return(Ptime);
break;
case 3: return(Pidelay);
break;
case 4: return(Pidelayfb);
break;
// case 5: return(Prdelay);
// break;
// case 6: return(Perbalance);
// break;
case 7: return(Plpf);
break;
case 8: return(Phpf);
break;
case 9: return(Plohidamp);
break;
case 10:return(Ptype);
break;
case 11:return(Proomsize);
break;
};
return(0);//in case of bogus "parameter"
};